/**
 * S3签名工具
 * 基于AWS签名算法V4实现，适配微信小程序环境
 */

const { S3_CONFIG, getEndpoint } = require('./config');
const CryptoJS = require('./crypto-js-mini'); // 注：需要为小程序环境提供适配的CryptoJS版本

/**
 * 生成ISO8601格式的日期字符串
 * @param {Date} date 日期对象
 * @returns {string} ISO8601格式的日期字符串
 */
function getISODate(date = new Date()) {
  return date.toISOString().replace(/[:-]|\.\d{3}/g, '');
}

/**
 * 获取日期部分
 * @param {string} isoDate ISO8601格式的日期字符串
 * @returns {string} 日期部分 (YYYYMMDD)
 */
function getDateStamp(isoDate) {
  return isoDate.substring(0, 8);
}

/**
 * 生成AWS签名密钥
 * @param {string} secretKey 密钥
 * @param {string} dateStamp 日期戳
 * @param {string} region 区域
 * @param {string} service 服务名称
 * @returns {ArrayBuffer} 签名密钥
 */
function getSignatureKey(secretKey, dateStamp, region, service) {
  const kDate = CryptoJS.HmacSHA256(dateStamp, 'AWS4' + secretKey);
  const kRegion = CryptoJS.HmacSHA256(region, kDate);
  const kService = CryptoJS.HmacSHA256(service, kRegion);
  const kSigning = CryptoJS.HmacSHA256('aws4_request', kService);
  return kSigning;
}

/**
 * 生成签名版本4请求头
 * @param {Object} options 请求选项
 * @param {string} options.method HTTP方法
 * @param {string} options.key 对象键
 * @param {Object} options.headers 请求头
 * @param {string} options.expires 过期时间（秒）
 * @returns {Object} 带有授权信息的请求头
 */
function generateV4Headers(options) {
  const { method = 'GET', key, headers = {}, expires } = options;
  const endpoint = getEndpoint();
  const accessKeyId = S3_CONFIG.accessKeyId;
  const secretAccessKey = S3_CONFIG.secretAccessKey;
  const region = S3_CONFIG.region;
  const bucketName = S3_CONFIG.bucketName;
  
  // 准备签名数据
  const isoDate = getISODate();
  const dateStamp = getDateStamp(isoDate);
  
  // 规范请求
  const canonicalURI = `/${key}`;
  const canonicalQueryString = '';
  const canonicalHeaders = 'host:' + new URL(endpoint).host + '\n' + 
                          'x-amz-date:' + isoDate + '\n';
  const signedHeaders = 'host;x-amz-date';
  
  // 哈希请求体
  const payloadHash = CryptoJS.SHA256('').toString(CryptoJS.enc.Hex);
  
  const canonicalRequest = method + '\n' + 
                          canonicalURI + '\n' + 
                          canonicalQueryString + '\n' + 
                          canonicalHeaders + '\n' + 
                          signedHeaders + '\n' + 
                          payloadHash;
  
  // 创建待签名字符串
  const algorithm = 'AWS4-HMAC-SHA256';
  const scope = dateStamp + '/' + region + '/s3/aws4_request';
  const stringToSign = algorithm + '\n' +
                      isoDate + '\n' +
                      scope + '\n' +
                      CryptoJS.SHA256(canonicalRequest).toString(CryptoJS.enc.Hex);
  
  // 计算签名
  const signingKey = getSignatureKey(secretAccessKey, dateStamp, region, 's3');
  const signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);
  
  // 构建授权头
  const authHeader = algorithm + ' ' +
                    'Credential=' + accessKeyId + '/' + scope + ', ' +
                    'SignedHeaders=' + signedHeaders + ', ' +
                    'Signature=' + signature;
  
  // 返回请求头
  return {
    'X-Amz-Date': isoDate,
    'Authorization': authHeader,
    ...headers
  };
}

/**
 * 生成预签名URL
 * @param {Object} options 请求选项
 * @param {string} options.method HTTP方法
 * @param {string} options.key 对象键
 * @param {number} options.expires 过期时间（秒）
 * @returns {string} 预签名URL
 */
function generatePresignedUrl(options) {
  const { method = 'GET', key, expires = 3600 } = options;
  const endpoint = getEndpoint();
  const accessKeyId = S3_CONFIG.accessKeyId;
  const secretAccessKey = S3_CONFIG.secretAccessKey;
  const region = S3_CONFIG.region;
  const bucketName = S3_CONFIG.bucketName;
  
  // 生成时间戳
  const isoDate = getISODate();
  const dateStamp = getDateStamp(isoDate);
  
  // 构建查询参数
  const amzDate = isoDate;
  const credential = accessKeyId + '/' + dateStamp + '/' + region + '/s3/aws4_request';
  const signedHeaders = 'host';
  
  // 构建URL参数
  const params = new URLSearchParams();
  params.append('X-Amz-Algorithm', 'AWS4-HMAC-SHA256');
  params.append('X-Amz-Credential', credential);
  params.append('X-Amz-Date', amzDate);
  params.append('X-Amz-Expires', expires);
  params.append('X-Amz-SignedHeaders', signedHeaders);
  
  // 构建规范请求
  const host = new URL(endpoint).host;
  const canonicalURI = `/${bucketName}/${key}`;
  const canonicalQueryString = params.toString();
  const canonicalHeaders = 'host:' + host + '\n';
  const payloadHash = 'UNSIGNED-PAYLOAD';
  
  const canonicalRequest = method + '\n' + 
                         canonicalURI + '\n' + 
                         canonicalQueryString + '\n' + 
                         canonicalHeaders + '\n' + 
                         signedHeaders + '\n' + 
                         payloadHash;
  
  // 创建待签名字符串
  const algorithm = 'AWS4-HMAC-SHA256';
  const scope = dateStamp + '/' + region + '/s3/aws4_request';
  const stringToSign = algorithm + '\n' +
                      amzDate + '\n' +
                      scope + '\n' +
                      CryptoJS.SHA256(canonicalRequest).toString(CryptoJS.enc.Hex);
  
  // 计算签名
  const signingKey = getSignatureKey(secretAccessKey, dateStamp, region, 's3');
  const signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);
  
  // 添加签名到查询参数
  params.append('X-Amz-Signature', signature);
  
  // 构建最终URL
  return `${endpoint}/${bucketName}/${key}?${params.toString()}`;
}

module.exports = {
  generateV4Headers,
  generatePresignedUrl
}; 